<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>14-阶段小结实践：购物车案例</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <style>
      * {
        margin: 0;
        padding: 0;
      }
      body {
        padding: 20px;
      }
      a {
        text-decoration: none;
      }
      ul {
        overflow: hidden;
      }
      ul li {
        list-style: none;
      }
      .cart {
        width: 330px;
        height: 360px;
        border: 1px solid #ccc;
        position: relative;
      }
      .my_commodity {
        line-height: 36px;
        background-color: rgb(255, 204, 0);
        text-align: center;
      }
      li {
        position: relative;
        padding: 0 15px;
        height: 39px;
        line-height: 39px;
        border-bottom: 1px dashed rgb(255, 204, 0);
      }
      li > div {
        float: left;
      }
      .commodity_l {
        padding-right: 30px;
      }
      .change {
        position: absolute;
        right: 70px;
        top: 0px;
      }
      .change > input {
        display: inline-block;
        width: 50px;
        height: 22px;
        height: 26px;
        padding-left: 13px;
        border-radius: 5px;
        border: 1px solid rgb(255, 204, 0);
        color: rgb(75, 73, 73);
      }
      .change > a {
        display: inline-block;
        width: 22px;
        height: 22px;
        border-radius: 50%;
        color: hotpink;
        font-weight: bold;
        font-size: 20px;
        line-height: 22px;
        text-align: center;
        background-color: rgb(255, 204, 0);
      }
      .commodity_r {
        float: right;
        width: 26px;
        height: 26px;
        background-color: hotpink;
        border-radius: 3px;
        text-align: center;
        line-height: 23px;
        margin-top: 5px;
        font-weight: bold;
        font-size: 22px;
        cursor: pointer;
      }
      .total {
        width: 100%;
        height: 50px;
        line-height: 50px;
        background-color: rgb(227, 116, 26);
        position: absolute;
        bottom: 0;
        left: 0;
      }
      .sum {
        float: right;
        font-size: 20px;
      }
      .sum > button {
        background-color: #fff;
        border-radius: 5px;
        padding: 6px 9px;
        border: none;
        margin: 0 30px;
        cursor: pointer;
      }
    </style>
  </head>
  <body>
    <div id="app">
      <my-cart></my-cart>
    </div>
    <script>
      var CartTitle = {
        // 1.2: 子组件接收后，需要通过props声明，才能在自己的template中使用了
        props: ['title'],
        template: `
        <div class="my_commodity">{{title}}的商品</div>
        `,
      };
      //4:<输入框修改商品数量>：:value绑定每个对象中的num，通过@blur触发自己的事件出来函数，
      // $event中包含了这个商品对象的信息，其中有商品id，和商品的value数量
      // 5:< -+商品数量增减 >： -+绑定的都是点击事件，触发自己的事件处理函数，并携带了ID
      var CartList = {
        props: ['list'],
        template: `
        <ul>
          <li v-for="item in list" :key="item.id">
            <div class="commodity_l"><span>{{item.name}}</span></div>
            <div class="change">
              <a href="javascript:;" @click.prevent="sub(item.id)">-</a>
              <input type="text" value="1" :value="item.num" @blur="changeNum(item.id, $event)" />
              <a href="javascript:;" @click.prevent="add(item.id)">+</a>
            </div>
            <div class="commodity_r" @click="del(item.id)">x</div>
          </li>
        </ul>
        `,
        methods: {
          // 3:<删除功能>：通过触发自己的事件函数，去发布自定义事件。
          del: function (id) {
            this.$emit('car-del', id);
          },
          //4.1:<输入框修改商品数量>：触发自己的事件处理函数，发布自定义事件，参数2是一个对象，包含了id和value数量，
          // 5.1: < -+商品数量增减 >：sub和add的事件处理方式是一致的，都是触发了change-num自定义事件，并携带了id
          changeNum: function (id, e) {
            this.$emit('change-num', {
              id: id,
              type: 'change',
              num: e.target.value,
            });
          },
          sub: function (id) {
            this.$emit('change-num', {
              id: id,
              type: 'sub',
            });
          },
          add: function (id) {
            this.$emit('change-num', {
              id: id,
              type: 'add',
            });
          },
        },
      };

      var CartTotal = {
        //2.2: <统计总价格>:接收父组件传递过来的数据
        props: ['datas'],
        // 2.5：<统计总价格>:将total函数的返回结果直接渲染到页面上，展示了商品的总价格
        template: `
        <div class="total">
          <div class="sum">
            <span>总价：￥{{total}}</span>
            <button>结算</button>
          </div>
        </div>
        `,
        // 2.3：<统计总价格>: 在计算属性中，定义了一个total函数，函数的返回值就是商品的sum总价格
        computed: {
          total: function () {
            var sum = 0;
            //2.4： <统计总价格>:循环每一个对象，将每个对象的价格和数量相乘，用sum累加，sum求到和就返回给函数
            this.datas.forEach((item) => {
              sum += item.price * item.num;
            });
            return sum;
          },
        },
      };

      Vue.component('my-cart', {
        data: function () {
          return {
            // 1：<修改购物车的用户>， 先在父组件中定义数据
            uname: '李雪儿',
            // 2：<统计总价格>: 先提供购物车列表的数据
            dataList: [
              {
                id: 1,
                name: '小米11手机',
                price: 1000,
                num: 1,
              },
              {
                id: 2,
                name: '好空调 - 格力造',
                price: 1000,
                num: 1,
              },
              {
                id: 3,
                name: '三星Utral系列',
                price: 1000,
                num: 1,
              },
              {
                id: 4,
                name: '华为路由器',
                price: 1000,
                num: 1,
              },
              {
                id: 5,
                name: '巨能写智能笔',
                price: 1000,
                num: 1,
              },
              {
                id: 6,
                name: '天暖保温杯',
                price: 1000,
                num: 1,
              },
            ],
          };
        },
        // 1.1：<修改购物车的用户> 通过：title接收父组件的数据
        // 2.1：<统计总价格> :将dataList护具通过：datas传递到cart-total子组件中
        // 3.1：<删除商品>：car-del="fatherDel($event)触发父组件的删除事件，
        // 4.2: <输入框修改商品数量>：@change-num触发了父组件的事件处理函数，$event中就是参数2，那个对象
        // 5.2: < -+商品数量增减 >：sub和add触发的都是同一个事件处理函数， @change-num="changeNumber($event)
        template: `
        <div class="cart">
          <cart-title :title="uname"></cart-title>
          <cart-list :list="dataList" @car-del="fatherDel($event)" @change-num="changeNumber($event)"></cart-list>
          <cart-total :datas="dataList"></cart-total>
        </div>
        `,
        components: {
          'cart-title': CartTitle,
          'cart-list': CartList,
          'cart-total': CartTotal,
        },
        methods: {
          // 3.2：触发了父组件的事件，通过findIndex找到id，根据id将使用splice删除掉一条商品
          fatherDel: function (id) {
            var index = this.dataList.findIndex((item) => {
              return item.id == id;
            });
            this.dataList.splice(index, 1);
          },
          // 4.3: <输入框修改商品数量>：父组件的事件处理函数，通过some根据id找出那个对象，在将输入框的e.num数量写入数组中，完成修改就return阻止some继续循环
          // 5.2: < -+商品数量增减 >：因为是共用了同一个事件处理函数，所以是通过e.type判断事件类型的，+-的处理方式也是一致的，通过some找到数组中的这项，再把数组中的每项item.num进行运算，实现了数组对象中num数量的修改。
          changeNumber: function (e) {
            if (e.type == 'change') {
              // console.log(e); //Object { id: 1, num: "2" }
              this.dataList.some((item) => {
                if (item.id == e.id) {
                  item.num = e.num;
                  return true;
                }
              });
            } else if (e.type == 'sub') {
              this.dataList.some((item) => {
                if (item.id == e.id) {
                  if (item.num == 1) {
                    return true;
                  } else {
                    item.num -= 1;
                    return true;
                  }
                }
              });
            } else if (e.type == 'add') {
              this.dataList.some((item) => {
                if (item.id == e.id) {
                  item.num += 1;
                  return true;
                }
              });
            }
          },
        },
      });
      var vm = new Vue({
        el: '#app',
        data: {},
        methods: {},
      });
    </script>
  </body>
</html>
